<template>
  <div>
    <el-switch
      style="display: block"
      v-model="readOnly"
      active-color="#13ce66"
      inactive-color="#ff4949"
      active-text="阅读模式"
      inactive-text="编辑模式"
    >
    </el-switch>
    <hr />
    <!--
      : v-bind的简写
      highlight-current 选中会高光,默认false
      expand-on-click-node 点击node的文字node就会展开,默认true
      data el-tree双向绑定的数据主体
      props 相关配置
      default-expanded-keys 默认展开的node
    -->
    <el-tree
      :highlight-current="true"
      :expand-on-click-node="false"
      :data="categories"
      :props="defaultProps"
      :default-expanded-keys="expandedKey"
      :allow-drop="allowDrop"
      :draggable="true"
      @node-drop="handleDrop"
      node-key="catId"
      ><span class="custom-tree-node" slot-scope="{ node, data }">
        <span>{{ node.label }}</span>
        <span v-show="!readOnly">
          <el-button
            v-show="data.catLevel <= 2"
            type="text"
            size="mini"
            @click="() => append(data)"
          >
            添加
          </el-button>
          <el-button type="text" size="mini" @click="() => edit(data)">
            修改
          </el-button>
          <el-button
            v-show="node.childNodes.length == 0"
            type="text"
            size="mini"
            @click="() => remove(node, data)"
          >
            删除
          </el-button>
        </span>
      </span></el-tree
    >
    <el-dialog
      :title="title"
      :visible.sync="dialogVisible"
      :close-on-click-modal="false"
      :close-on-press-escape="true"
      :show-close="true"
      width="30%"
    >
      <el-form :model="category">
        <el-form-item v-show="category.showForAppend" label="分类名称">
          <el-input v-model="category.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item v-show="category.showForEdit" label="分类名称">
          <el-input v-model="category.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item v-show="category.showForEdit" label="图标">
          <el-input v-model="category.icon" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item v-show="category.showForEdit" label="计量单位">
          <el-input
            v-model="category.productUnit"
            autocomplete="off"
          ></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="cancelOperation">取 消</el-button>
        <el-button type="primary" @click="submitData">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
export default {
  data() {
    return {
      // 树是否只读
      readOnly: true,
      // 对话dialog的标题
      title: "默认标题",
      // 对话的类型
      dialogType: "默认对话类型",
      formLabelWidth: "120px",
      category: {
        // 以下是数据库的字段
        name: "",
        parentCid: 0,
        catLevel: 0,
        showStatus: 1,
        sort: -1,
        catId: null,
        icon: null,
        productUnit: null,
        // 以下是用来操控form的动态显示的布尔值
        showForAppend: false,
        showForEdit: false,
      },

      // 与tree双向绑定的数据
      categories: [],
      // 与tree双向绑定的数据
      expandedKey: [],
      // 控制对话是否可见的布尔值
      dialogVisible: false,

      // tree的一些配置属性,详见elementUI官方文档
      defaultProps: {
        children: "children",
        label: "name",
      },
    };
  },

  methods: {
    // 发送post请求
    postRequest(url, data) {
      this.$http({
        url: this.$http.adornUrl(url),
        method: "post",
        data: this.$http.adornData(data, false),
      });
    },
    // 初始化所有的 sort
    setValueForAllSort(categories) {
      let category = { catId: -1, sort: -1 };
      for (let i = 0; i < categories.length; i++) {
        category.catId = categories[i].catId;
        category.sort = i;
        this.$http({
          url: this.$http.adornUrl("/product/category/update"),
          method: "post",
          data: this.$http.adornData(category, false),
        });
        categories[i].sort = i;
        for (let j = 0; j < categories[i].children.length; j++) {
          category.catId = categories[i].children[j].catId;
          category.sort = j;
          this.$http({
            url: this.$http.adornUrl("/product/category/update"),
            method: "post",
            data: this.$http.adornData(category, false),
          });
          categories[i].children[j].sort = j;
          for (let k = 0; k < categories[i].children[j].children.length; k++) {
            category.catId = categories[i].children[j].children[k].catId;
            category.sort = k;
            this.$http({
              url: this.$http.adornUrl("/product/category/update"),
              method: "post",
              data: this.$http.adornData(category, false),
            });
            categories[i].children[j].children[k].sort = k;
          }
        }
      }
      this.categories = categories;
    },
    // 如果是往 上 拖拽并且提示消息在XXX的 下面 范围就是 hisSort+1 ~ mySort
    // 如果是往 下 拖拽并且提示消息在XXX的 上面 范围就是 mySort ~ hisSort-1
    // 如果是往 下 拖拽并且提示消息在XXX的 下面 范围就是 mySort ~ hisSort
    // 拖动后的处理方法
    handleDrop(draggingNode, dropNode, dropType, ev) {
      // 由于sort变化只会影响到最大sort上面的sort,所以需要找出需要修改数据的区间
      let mySort = draggingNode.data.sort;
      let hisSort = dropNode.data.sort;
      // let maxBetweenTwoSort;
      // if (mySort > hisSort) {
      //   maxBetweenTwoSort = mySort;
      // } else {
      //   maxBetweenTwoSort = hisSort;
      // }

      // 增量
      let increase = 0;
      // 如果是往 上 拖拽并且提示消息在XXX的 下面 范围就是 hisSort+1 ~ mySort
      if (mySort - hisSort > 0 && dropType == "after") {
        dropType = "下面";
        increase = 1;
      }
      // 如果是往 上 拖拽并且提示消息在XXX的 上面,范围就是 hisSort ~ mySort
      if (mySort - hisSort > 0 && dropType == "before") {
        dropType = "上面";
        // 先是my的sort变成hisSort,其余的节点的sort+1
        // 组装myCategory
        let myCategory = {
          catId: draggingNode.data.catId,
          sort: hisSort + increase,
        };
        let categoryArray = new Array();
        for (let i = 0; i < this.categories.length; i++) {
          if (
            this.categories[i].sort <= hisSort + increase &&
            this.categories[i].sort >= mySort
          ) {
            let commonCategory = {
              catId: this.categories[i].catId,
              sort: this.categories[i].sort + 1,
            };
            categoryArray.push([commonCategory]);
          }
        }
        console.log(categoryArray);
        // // 发请求修改数据
        //     this.postRequest("/product/category/update", commonCategory);
        // // 发请求修改数据
        // this.postRequest("/product/category/update", myCategory);
        // // 查询所有数据
        // this.getMenus();
        // // 展开父节点
        // if (draggingNode.data.catLevel == 1) {
        //   this.expandedKey = [draggingNode.data.parentCid];
        // }
      }
      // 帮助信息
      console.log(
        "%c!<-------------------- 拖拽数据 start -------------------->",
        "color:blue"
      );
      console.log(
        draggingNode,
        dropNode,
        "【" +
          draggingNode.label +
          "】" +
          " 移动到 " +
          "【" +
          dropNode.label +
          "】" +
          " " +
          dropType
      );
      console.log(
        "%c!<-------------------- 拖拽数据 end -------------------->",
        "color:blue"
      );
      // // 得到层级
      // let level = draggingNode.data.catLevel;
      // switch (level) {
      //   // 说明是第1层,那么没有父节点
      //   case 1: {
      //     // 被交换的节点的真实sort需要分类讨论，我的思路是先得到那个被交换的节点的真正的sort,然后再数据库里交换一下就完事
      //     // 如果提示是移动到xx上方
      //     if (dropType === "上方") {
      //       hisSort = dropNode.data.sort - 1;
      //     }
      //     // 如果提示是移动到xx下方
      //     if (dropType === "下方") {
      //       hisSort = dropNode.data.sort + 1;
      //     }
      //     // 得到自己的sort
      //     mySort = draggingNode.data.sort;
      //     // 组装两个category
      //     myCategory.catId = draggingNode.data.catId;
      //     // 交换sort
      //     myCategory.sort = hisSort;
      //     hisCategory.sort = mySort;
      //     // 获取被替换的节点的ID
      //     for (let i = 0; i < this.categories.length; i++) {
      //       if (this.categories[i].sort == hisSort) {
      //         hisCategory.catId = this.categories[i].catId;
      //       }
      //     }
      // 如果两个相邻则互换sort
      // if (mySort - hisSort == 1 || mySort - hisSort == -1) {
      //   console.log("本次互换的节点相邻");
      //   let temp = mySort;
      //   mySort = hisSort;
      //   hisSort = temp;
      // }
      // 不相邻
      // if (mySort - hisSort != 1 && mySort - hisSort != -1) {
      // 得到自己的sort和被换的节点的sort
      // console.log("本次互换的节点不相邻");
      // mySort = draggingNode.data.sort;
      // hisSort = dropNode.data.sort;
      // let increment = 0;
      // // 组装
      // myCategory.catId = draggingNode.data.catId;
      // // 注意这里的 -1
      // myCategory.sort = dropNode.data.sort + increment;
      // hisCategory.sort = mySort;
      // 然后发请求修改两个sort
      //     this.$http({
      //       url: this.$http.adornUrl("/product/category/update"),
      //       method: "post",
      //       data: this.$http.adornData(myCategory, false),
      //     });
      //     this.$http({
      //       url: this.$http.adornUrl("/product/category/update"),
      //       method: "post",
      //       data: this.$http.adornData(hisCategory, false),
      //     }).then(() => {
      //       // 发送消息,提示交换情况
      //       this.showMessage(
      //         "info",
      //         true,
      //         "【" +
      //           draggingNode.label +
      //           "】" +
      //           " 移动到 " +
      //           "【" +
      //           dropNode.label +
      //           "】 " +
      //           dropType
      //       );
      //       // 查询所有数据
      //       this.getMenus();
      //       // 展开父节点
      //       if (draggingNode.data.catLevel == 1) {
      //         this.expandedKey = [draggingNode.data.parentCid];
      //       }
      //     });
      //   }
      //   case 2: {
      //     // 说明是第2层
      //   }
      //   case 3: {
      //     // 说明是第3层
      //   }
      // }
    },

    // 控制某些节点是否可以通过拖拽移动位置
    allowDrop(draggingNode, dropNode, type) {
      // 约定: 只能同级别拖动
      // console.log(draggingNode, dropNode, type);
      if (draggingNode.data.parentCid != dropNode.data.parentCid) {
        return false;
      }
      switch (type) {
        case "next":
        case "prev":
          return true;
        case "inner":
          return false;
      }
    },

    // 展示消息
    showMessage(type, isTextCenter, content) {
      this.$message({
        // 消息类型
        type: type,
        // 消息的位子是否居中
        center: isTextCenter,
        // 消息内容
        message: content,
      });
    },

    // 点击对话框的确定按钮调用的方法
    submitData() {
      // 根据对话框的目的来调用不同的方法
      if (this.dialogType == "add") {
        // 执行添加
        this.addCategory();
        // 使name不再回显
        this.category.name = "";
      }
      if (this.dialogType == "edit") {
        // 执行编辑
        this.editCategory();
      }
    },

    // 执行编辑操作
    editCategory() {
      // 先列出需要提交数据库的字段
      // catId 需要通过此字段来定位数据
      let { catId, name, icon, productUnit } = this.category;
      let data = {
        catId: catId,
        name: name,
        icon: icon,
        productUnit: productUnit,
      };
      console.log(data);
      // 发送请求
      this.$http({
        url: this.$http.adornUrl("/product/category/update"),
        method: "post",
        data: this.$http.adornData(data, false),
      }).then(() => {
        // 使对话框不可见
        this.dialogVisible = false;
        // 提示消息
        this.showMessage("success", true, "修改成功!");
        // 刷新数据
        this.getMenus();
        // 展开父节点(排除没有父节点的节点)
        if (this.category.parentCid != 0) {
          this.expandedKey = [this.category.parentCid];
        }
      });
    },

    // 执行添加操作
    addCategory() {
      // 列出需要上传数据库的字段
      let { name, parentCid, catLevel, showStatus, sort } = this.category;
      let data = { name, parentCid, catLevel, showStatus, sort };
      console.log(data);
      // 关闭对话框
      this.dialogVisible = false;
      // 发送请求
      this.$http({
        url: this.$http.adornUrl("/product/category/save"),
        method: "post",
        data: this.$http.adornData(data, false),
      }).then(() => {
        this.showMessage("success", true, "添加成功!");
        // 刷新数据
        this.getMenus();
        // 展开父节点
        this.expandedKey = [this.category.parentCid];
      });
    },

    // 对话框的取消按钮的单击事件
    cancelOperation() {
      // 使对话框不可见
      this.dialogVisible = false;
      this.showMessage("info", true, "操作取消");
      console.log(this.categories);
    },

    // 从数据库获取全部分类数据
    getMenus() {
      this.$http({
        url: this.$http.adornUrl("/product/category/list/tree"),
        method: "get",
      }).then(({ data }) => {
        console.log(data);
        this.categories = data.categories;
        // 先重置category表再运行此方法!!! 这个方法是给所有sort赋值用的
        // this.setValueForAllSort(this.categories);
        console.log(this.categories);
      });
    },

    // 添加按钮的单机事件
    append(data) {
      console.log(data);
      // 设定对话框的标题
      this.title = "添加分类";
      // 设定对话框的类型
      this.dialogType = "add";
      // 使对话框可见
      this.dialogVisible = true;
      // 调整输入框的可见性
      this.category.showForAppend = true;
      this.category.showForEdit = false;
      // 给category赋新值(catId:主键自增)
      this.category.parentCid = data.catId;
      this.category.showStatus = 1;
      // 分情况讨论sort的值
      // 1 父节点的子节点不为空
      if (data.children.length != 0) {
        // 那就默认排在最后一个
        this.category.sort = data.children.length;
      }
      // 2 父节点的子节点为空,默认排在第一个
      this.category.sort = 0;

      this.category.catLevel = data.catLevel * 1 + 1;
    },

    // 删除按钮的单机事件
    remove(node, data) {
      this.title = "删除分类";
      let ids = [data.catId];
      this.$confirm(`是否删除分类【${data.name}】?`, "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.$http({
            url: this.$http.adornUrl("/product/category/delete"),
            method: "post",
            data: this.$http.adornData(ids, false),
          }).then(() => {
            this.showMessage("success", true, "删除成功!");
            // 刷新数据
            this.getMenus();
            // 得到被删除的节点的父节点的Id,并展开父节点
            this.expandedKey = [node.parent.data.catId];
          });
        })
        .catch(() => {
          this.showMessage("info", true, "操作取消");
        });
    },

    // 编辑按钮的单击事件
    edit(data) {
      this.title = "修改分类";
      this.dialogType = "edit";
      // 调整输入框的可见性
      this.category.showForAppend = false;
      this.category.showForEdit = true;
      // 使对话框可见
      this.dialogVisible = true;
      // 发送请求获取最新数据
      this.$http({
        url: this.$http.adornUrl(`/product/category/info/${data.catId}`),
        method: "get",
        params: this.$http.adornParams({}),
      }).then(({ data }) => {
        // 给catgory赋新值
        this.category.name = data.category.name;
        this.category.catId = data.category.catId;
        this.category.icon = data.category.icon;
        this.category.productUnit = data.category.productUnit;
      });
    },
  },

  // 声明周期-创建时
  created() {
    // 从数据库获取数据
    this.getMenus();
  },
};
</script>

<style>
</style>